FastAPI ning kuchli bog'liqlikni kiritish tizimini chuqurroq o'rganing. Mustahkam API ishlab chiqish uchun ilg'or texnikalar, maxsus bog'liqliklar, ko'lamlar va sinov strategiyalarini o'rganing.
FastAPI bog'liqlik tizimi: Kengaytirilgan bog'liqlikni kiritish
FastAPI ning bog'liqlikni kiritish (DI) tizimi uning dizaynining asosiy toshidir, bu modullik, sinov qobiliyati va qayta foydalanishni rag'batlantiradi. Asosiy foydalanish sodda bo'lsa-da, ilg'or DI texnikasini o'zlashtirish sezilarli kuch va moslashuvchanlikni ochadi. Ushbu maqola FastAPI da ilg'or bog'liqlikni kiritishga, maxsus bog'liqliklarni, ko'lamlarni, sinov strategiyalarini va eng yaxshi amaliyotlarni qamrab oladi.
Asoslarni tushunish
Ilg'or mavzularga sho'ng'ishdan oldin, FastAPI ning bog'liqlikni kiritish asoslarini qisqacha ko'rib chiqaylik:
- Bog'liqliklar funksiyalar sifatida: Bog'liqliklar oddiy Python funksiyalari sifatida e'lon qilinadi.
- Avtomatik in'ektsiya: FastAPI avtomatik ravishda bu bog'liqliklarni turdagi maslahatlarga asoslangan yo'l operatsiyalariga kiritadi.
- Turi maslahatlari shartnomalar sifatida: Turi maslahatlari bog'liqliklar va yo'l operatsiyasi funksiyalari uchun kutilgan kirish turlarini belgilaydi.
- Ierarxik bog'liqliklar: Bog'liqliklar boshqa bog'liqliklarga bog'liq bo'lishi mumkin, bu esa bog'liqlik daraxtini yaratadi.
Mana oddiy misol:
from fastapi import FastAPI, Depends
app = FastAPI()
def get_db():
db = {"items": []}
try:
yield db
finally:
# Agar kerak bo'lsa, ulanishni yoping
pass
@app.get("/items/")
async def read_items(db: dict = Depends(get_db)):
return db["items"]
Ushbu misolda get_db - bu ma'lumotlar bazasi ulanishini ta'minlaydigan bog'liqlik. FastAPI avtomatik ravishda get_db ni chaqiradi va natijani read_items funksiyasiga kiritadi.
Ilg'or bog'liqlik texnikasi
1. Klasslardan bog'liqlik sifatida foydalanish
Funksiyalardan keng qo'llanilishiga qaramay, klasslar yanada murakkab holatni boshqarish va usullar uchun ruxsat berib, bog'liqlik sifatida ham xizmat qilishi mumkin. Bu, ayniqsa, ma'lumotlar bazasi ulanishlari, autentifikatsiya xizmatlari yoki initsializatsiya va tozalashni talab qiladigan boshqa resurslar bilan ishlashda foydalidir.
from fastapi import FastAPI, Depends
app = FastAPI()
class Database:
def __init__(self):
self.connection = self.create_connection()
def create_connection(self):
# Ma'lumotlar bazasi ulanishini simulyatsiya qilish
print("Ma'lumotlar bazasi ulanishini yaratish...")
return {"items": []}
def close(self):
# Ma'lumotlar bazasi ulanishini yopishni simulyatsiya qilish
print("Ma'lumotlar bazasi ulanishini yopish...")
def get_db():
db = Database()
try:
yield db.connection
finally:
db.close()
@app.get("/items/")
async def read_items(db: dict = Depends(get_db)):
return db["items"]
Ushbu misolda Database klassi ma'lumotlar bazasi ulanish mantig'ini o'z ichiga oladi. get_db bog'liqligi Database klassining namunalarini yaratadi va ulanishni ta'minlaydi. finally bloki so'rov qayta ishlanganidan keyin ulanish to'g'ri yopilishini ta'minlaydi.
2. Bog'liqliklarni bekor qilish
FastAPI sizga bog'liqliklarni bekor qilishga imkon beradi, bu sinov va ishlab chiqish uchun juda muhimdir. Kodingizni izolyatsiya qilish va izchil natijalarni ta'minlash uchun haqiqiy bog'liqlikni mock yoki stub bilan almashtirishingiz mumkin.
from fastapi import FastAPI, Depends
app = FastAPI()
# Asl bog'liqlik
def get_settings():
# Fayl yoki muhitdan sozlamalarni yuklashni simulyatsiya qilish
return {"api_key": "real_api_key"}
@app.get("/items/")
async def read_items(settings: dict = Depends(get_settings)):
return {"api_key": settings["api_key"]}
# Sinov uchun bekor qilish
def get_settings_override():
return {"api_key": "test_api_key"}
app.dependency_overrides[get_settings] = get_settings_override
# Asliga qaytarish uchun:
# del app.dependency_overrides[get_settings]
Ushbu misolda get_settings bog'liqligi get_settings_override bilan bekor qilingan. Bu sizga sinov maqsadlarida boshqa API kalitidan foydalanishga imkon beradi.
3. So'rov ko'lami ma'lumotlari uchun contextvars dan foydalanish
contextvars - kontekst-mahalliy o'zgaruvchilarni ta'minlaydigan Python moduli. Bu foydalanuvchi autentifikatsiya ma'lumotlari, so'rov IDlari yoki kuzatish ma'lumotlari kabi so'rovga xos ma'lumotlarni saqlash uchun foydalidir. contextvars dan FastAPI ning bog'liqlikni kiritish bilan birgalikda foydalanish sizga ushbu ma'lumotlarga butun ilovangizda kirishga imkon beradi.
import contextvars
from fastapi import FastAPI, Depends, Request
app = FastAPI()
# So'rov identifikatori uchun kontekst o'zgaruvchisini yaratish
request_id_var = contextvars.ContextVar("request_id")
# So'rov identifikatorini o'rnatish uchun oraliq dastur
@app.middleware("http")
async def add_request_id(request: Request, call_next):
request_id = str(uuid.uuid4())
request_id_var.set(request_id)
response = await call_next(request)
response.headers["X-Request-ID"] = request_id
return response
# So'rov identifikatoriga kirish uchun bog'liqlik
def get_request_id():
return request_id_var.get()
@app.get("/items/")
async def read_items(request_id: str = Depends(get_request_id)):
return {"request_id": request_id}
Ushbu misolda oraliq dastur har bir kiruvchi so'rov uchun noyob so'rov IDsini o'rnatadi. get_request_id bog'liqligi so'rov IDsini contextvars kontekstidan oladi. Bu sizga ilovangiz bo'ylab so'rovlarni kuzatib borishga imkon beradi.
4. Asinxron bog'liqliklar
FastAPI asinxron bog'liqliklarni uzluksiz qo'llab-quvvatlaydi. Bu ma'lumotlar bazasi so'rovlari yoki tashqi API qo'ng'iroqlari kabi blokirovka qilmaydigan I/U operatsiyalari uchun juda muhimdir. Oddiygina bog'liqlik funksiyangizni async def funksiyasi sifatida belgilang.
from fastapi import FastAPI, Depends
import asyncio
app = FastAPI()
async def get_data():
# Asinxron operatsiyani simulyatsiya qilish
await asyncio.sleep(1)
return {"message": "Asinxron bog'liqlikdan salom!"}
@app.get("/items/")
async def read_items(data: dict = Depends(get_data)):
return data
Ushbu misolda get_data bog'liqligi kechikishni simulyatsiya qiladigan asinxron funksiyadir. FastAPI avtomatik ravishda asinxron bog'liqlik natijasini read_items funksiyasiga kiritishdan oldin kutadi.
5. Resurslarni boshqarish uchun generatorlardan foydalanish (Ma'lumotlar bazasi ulanishlari, Fayl tutqichlari)
Generatorlardan (yield bilan) foydalanish avtomatik resurslarni boshqarishni ta'minlaydi, xatolar yuzaga kelganda ham finally blok orqali resurslar to'g'ri yopilishini/chiqarilishini kafolatlaydi.
from fastapi import FastAPI, Depends
app = FastAPI()
def get_file_handle():
try:
file_handle = open("my_file.txt", "r")
yield file_handle
finally:
file_handle.close()
@app.get("/file_content/")
async def read_file_content(file_handle = Depends(get_file_handle)):
content = file_handle.read()
return {"content": content}
Bog'liqlik ko'lamlari va hayot aylanishlari
Bog'liqlik ko'lamlarini tushunish bog'liqliklarning hayot aylanishini boshqarish va resurslar to'g'ri taqsimlanishi va chiqarilishini ta'minlash uchun juda muhimdir. FastAPI boshqa ba'zi DI freymvorklari (masalan, Spring ning @RequestScope, @ApplicationScope) kabi aniq ko'lam an'analarini bevosita taklif qilmaydi, lekin siz bog'liqliklarni qanday belgilashingiz va davlatni boshqarishingiz kombinatsiyasi shunga o'xshash natijalarga erishadi.
So'rov ko'lami
Bu eng keng tarqalgan ko'lam. Har bir so'rov bog'liqlikning yangi nusxasini oladi. Bu odatda bog'liqlik funksiyasida yangi ob'ektni yaratish va uni ta'minlash orqali amalga oshiriladi, bu avvalgi Ma'lumotlar bazasi misolida ko'rsatilgan. Contextvars dan foydalanish ham so'rov ko'lamiga erishishga yordam beradi.
Ilova ko'lami (Singleton)
Bog'liqlikning bitta nusxasi yaratiladi va butun ilovaning hayot aylanishi davomida barcha so'rovlar uchun baham ko'riladi. Bu ko'pincha global o'zgaruvchilar yoki klass darajasidagi atributlardan foydalanish orqali amalga oshiriladi.
from fastapi import FastAPI, Depends
app = FastAPI()
# Singleton namunasi
GLOBAL_SETTING = {"api_key": "global_api_key"}
def get_global_setting():
return GLOBAL_SETTING
@app.get("/items/")
async def read_items(setting: dict = Depends(get_global_setting)):
return setting
Agar o'zgaruvchan holatga ega bo'lgan ilovaga mo'ljallangan bog'liqliklardan foydalanayotganda ehtiyot bo'ling, chunki bir so'rov tomonidan qilingan o'zgarishlar boshqa so'rovlarga ta'sir qilishi mumkin. Agar ilovangiz parallel so'rovlarga ega bo'lsa, sinxronlashtirish mexanizmlari (qulflar va boshqalar) kerak bo'lishi mumkin.
Sessiya ko'lami (Foydalanuvchiga xos ma'lumotlar)
Bog'liqliklarni foydalanuvchi sessiyalari bilan bog'lang. Bu sessiyani boshqarish mexanizmini (masalan, kukilar yoki JWTlardan foydalanish) talab qiladi va odatda bog'liqliklarni sessiya ma'lumotlarida saqlashni o'z ichiga oladi.
from fastapi import FastAPI, Depends, Cookie
from typing import Optional
import uuid
app = FastAPI()
# Haqiqiy ilovada sessiyalarni ma'lumotlar bazasida yoki keshda saqlang
sessions = {}
async def get_user_id(session_id: Optional[str] = Cookie(None)) -> str:
if session_id is None or session_id not in sessions:
session_id = str(uuid.uuid4())
sessions[session_id] = {"user_id": str(uuid.uuid4())} # Tasodifiy foydalanuvchi IDsini tayinlash
return sessions[session_id]["user_id"]
@app.get("/profile/")
async def read_profile(user_id: str = Depends(get_user_id)):
return {"user_id": user_id}
Bog'liqliklarni sinovdan o'tkazish
Bog'liqlikni kiritishning asosiy afzalliklaridan biri bu yaxshilangan sinov qobiliyatidir. Komponentlarni ajratib, siz sinov paytida bog'liqliklarni osongina mock yoki stub bilan almashtirishingiz mumkin.
1. Sinovlarda bog'liqliklarni bekor qilish
Avval ko'rsatib o'tilganidek, FastAPI ning dependency_overrides mexanizmi sinov uchun idealdir. Kutilgan natijalarni qaytaradigan mock bog'liqliklarini yarating va ularni sinov ostidagi kodni izolyatsiya qilish uchun ishlating.
from fastapi.testclient import TestClient
from fastapi import FastAPI, Depends
app = FastAPI()
# Asl bog'liqlik
def get_external_data():
# Tashqi API dan ma'lumotlarni olishni simulyatsiya qilish
return {"data": "Haqiqiy tashqi ma'lumotlar"}
@app.get("/data/")
async def read_data(data: dict = Depends(get_external_data)):
return data
# Sinov
from unittest.mock import MagicMock
def get_external_data_mock():
return {"data": "Mocked external data"}
def test_read_data():
app.dependency_overrides[get_external_data] = get_external_data_mock
client = TestClient(app)
response = client.get("/data/")
assert response.status_code == 200
assert response.json() == {"data": "Mocked external data"}
# Bekor qilishni tozalash
app.dependency_overrides.clear()
2. Mocking kutubxonalaridan foydalanish
unittest.mock kabi kutubxonalar mock ob'ektlarni yaratish va ularning xatti-harakatlarini boshqarish uchun kuchli vositalarni taqdim etadi. Siz murakkab bog'liqliklarni simulyatsiya qilish va kodning ular bilan to'g'ri o'zaro ta'sirini tekshirish uchun mocklardan foydalanishingiz mumkin.
import unittest
from unittest.mock import MagicMock
# (FastAPI ilovasini va yuqoridagi kabi get_external_data ni aniqlang)
class TestReadData(unittest.TestCase):
def test_read_data_with_mock(self):
# get_external_data bog'liqligi uchun mock yarating
mock_get_external_data = MagicMock(return_value={"data": "Mocked data from unittest"})
# Bog'liqlikni mock bilan bekor qilish
app.dependency_overrides[get_external_data] = mock_get_external_data
client = TestClient(app)
response = client.get("/data/")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), {"data": "Mocked data from unittest"})
# Mockning chaqirilganligini tasdiqlash
mock_get_external_data.assert_called_once()
# Bekor qilishni tozalash
app.dependency_overrides.clear()
3. Birlik sinovi uchun bog'liqlikni kiritish (FastAPI kontekstidan tashqarida)
API so'nggi ishlov beruvchilardan tashqarida funksiyalarni birlik sinovidan o'tkazganda ham, bog'liqlikni kiritish tamoyillari qo'llaniladi. FastAPI ning Dependsiga tayanmasdan, bog'liqliklarni qo'lda sinov ostidagi funksiyaga kiriting.
# Sinovdan o'tkaziladigan misol funksiya
def process_data(data_source):
data = data_source.fetch_data()
# ... ma'lumotlarni qayta ishlash ...
return processed_data
class MockDataSource:
def fetch_data(self):
return {"example": "data"}
# Birlik sinovi
def test_process_data():
mock_data_source = MockDataSource()
result = process_data(mock_data_source)
# Natija bo'yicha tasdiqlar
Bog'liqlikni kiritish bilan xavfsizlik masalalari
Bog'liqlikni kiritish, foydali bo'lsa-da, agar ehtiyotkorlik bilan amalga oshirilmasa, potentsial xavfsizlik muammolarini keltirib chiqaradi.
1. Bog'liqlik chalkashligi
Bog'liqliklarni ishonchli manbalardan tortayotganingizga ishonch hosil qiling. Paket yaxlitligini tekshiring va zaiflikni skanerlash qobiliyatiga ega bo'lgan paket menejerlaridan foydalaning. Bu umumiy dasturiy ta'minot ta'minot zanjirining xavfsizlik printsipi, lekin DI tomonidan kuchaytiriladi, chunki siz turli manbalardan komponentlarni kiritishingiz mumkin.
2. Zararli bog'liqliklarni kiritish
To'g'ri tekshiruvlarsiz tashqi kiritishni qabul qiladigan bog'liqliklarga e'tibor bering. Hujumchi buzilgan bog'liqlik orqali zararli kod yoki ma'lumotlarni kiritishi mumkin. Barcha foydalanuvchi kiritmalarini tozalang va mustahkam tekshirish mexanizmlarini amalga oshiring.
3. Bog'liqliklar orqali ma'lumotlarning sizilishi
Bog'liqliklar tasodifan maxfiy ma'lumotlarni oshkor qilmasligiga ishonch hosil qiling. Potentsial ma'lumotlarning sizilishiga zaifliklarni aniqlash uchun bog'liqliklaringizning kodini va konfiguratsiyasini ko'rib chiqing.
4. Qattiq kodlangan sirlar
Sirlarni (API kalitlari, ma'lumotlar bazasi parollari va boshqalar) to'g'ridan-to'g'ri bog'liqlik kodingizga qattiq kodlashdan saqlaning. Sirlarni saqlash va boshqarish uchun muhit o'zgaruvchilaridan yoki xavfsiz konfiguratsiyani boshqarish vositalaridan foydalaning.
import os
from fastapi import FastAPI, Depends
app = FastAPI()
def get_api_key():
api_key = os.environ.get("API_KEY")
if not api_key:
raise ValueError("API_KEY atrof-muhit o'zgaruvchisi o'rnatilmagan.")
return api_key
@app.get("/secure_endpoint/")
async def secure_endpoint(api_key: str = Depends(get_api_key)):
# Autentifikatsiya/avtorizatsiya uchun api_key dan foydalaning
return {"message": "Ruxsat berildi"}
Unumdorlikni optimallashtirish bilan bog'liqlikni kiritish
Agar ehtiyotkorlik bilan ishlatilmasa, bog'liqlikni kiritish unumdorlikka ta'sir qilishi mumkin. Mana ba'zi optimallashtirish strategiyalari:
1. Bog'liqlikni yaratish narxini kamaytirish
Iloji bo'lsa, har bir so'rovda qimmat bog'liqliklarni yaratishdan saqlaning. Agar bog'liqlik shtatsiz bo'lsa yoki so'rovlar bo'yicha baham ko'rish mumkin bo'lsa, singleton ko'lamidan foydalanish yoki bog'liqlik misolini kesh qilishni ko'rib chiqing.
2. Dangasa initsializatsiya
Bog'liqliklarni faqat kerak bo'lganda initsializatsiya qiling. Bu ayniqsa ko'plab bog'liqliklarga ega bo'lgan ilovalar uchun ishga tushirish vaqtini va xotirani sarflashni kamaytirishi mumkin.
3. Bog'liqlik natijalarini kesh qilish
Agar natijalar qayta ishlatilishi ehtimoli bo'lsa, qimmat bog'liqlik hisob-kitoblarining natijalarini kesh qiling. Bog'liqlik natijalarini saqlash va olish uchun kesh mexanizmlaridan (masalan, Redis, Memcached) foydalaning.
4. Bog'liqlik grafigini optimallashtirish
Potentsial muammolarni aniqlash uchun bog'liqlik grafigingizni tahlil qiling. Agar iloji bo'lsa, bog'liqlik tuzilishini soddalashtiring va bog'liqliklar sonini kamaytiring.
5. I/U bog'langan operatsiyalar uchun asinxron bog'liqliklar
Bloklovchi I/U operatsiyalarni bajarishda, masalan, ma'lumotlar bazasi so'rovlari yoki tashqi API qo'ng'iroqlarini bajarishda asinxron bog'liqliklardan foydalaning. Bu asosiy ipni blokirovka qilishning oldini oladi va umumiy ilovaning javob berish qobiliyatini yaxshilaydi.
FastAPI bog'liqlikni kiritish uchun eng yaxshi amaliyotlar
- Bog'liqliklarni oddiy saqlang: Bitta vazifani bajaradigan kichik, fokuslangan bog'liqliklarga intiling. Bu o'qish qobiliyatini, sinov qobiliyatini va texnik xizmat ko'rsatishni yaxshilaydi.
- Turi maslahatlaridan foydalaning: Bog'liqliklarning kutilgan kirish va chiqish turlarini aniq belgilash uchun turi maslahatlaridan foydalaning. Bu kodning aniqligini oshiradi va FastAPI ga statik turdagi tekshiruvni amalga oshirishga imkon beradi.
- Bog'liqliklarni hujjatlashtiring: Har bir bog'liqlikning maqsadi va foydalanishini hujjatlashtiring. Bu boshqa ishlab chiquvchilarga kodingizdan qanday foydalanish va unga xizmat ko'rsatishni tushunishga yordam beradi.
- Bog'liqliklarni sinchkovlik bilan sinovdan o'tkazing: Kutilganidek harakat qilishlarini ta'minlash uchun bog'liqliklaringiz uchun birlik testlarini yozing. Bu xatoliklarning oldini olishga va ilovangizning umumiy ishonchliligini oshirishga yordam beradi.
- Izchil nomlash konventsiyalaridan foydalaning: Kodning o'qilishini yaxshilash uchun bog'liqliklaringiz uchun izchil nomlash konventsiyalaridan foydalaning.
- Aylanma bog'liqliklardan saqlaning: Aylanma bog'liqliklar murakkab va tuzatish qiyin bo'lgan kodga olib kelishi mumkin. Aylanma bog'liqliklarni yo'q qilish uchun kodingizni qayta ishlash.
- Bog'liqlikni kiritish konteynerlarini ko'rib chiqing (Ixtiyoriy): FastAPI ning o'rnatilgan bog'liqlikni kiritishi ko'pgina holatlar uchun etarli bo'lsa-da, yanada murakkab ilovalar uchun maxsus bog'liqlikni kiritish konteyneridan (masalan,
inject,autowire) foydalanishni ko'rib chiqing.
Xulosa
FastAPI ning bog'liqlikni kiritish tizimi modullikni, sinov qobiliyatini va qayta foydalanishni rag'batlantiradigan kuchli vositadir. Ilg'or texnikalarni, masalan, klasslardan bog'liqlik sifatida foydalanish, bog'liqliklarni bekor qilish va contextvars dan foydalanish, siz mustahkam va kengaytiriladigan APIlar yaratishingiz mumkin. Resurslarni samarali boshqarish uchun bog'liqlik ko'lamlarini va hayot aylanishlarini tushunish juda muhimdir. Ilovalaringizning ishonchliligi va xavfsizligini ta'minlash uchun har doim bog'liqliklaringizni sinovdan o'tkazishga ustuvorlik bering. Eng yaxshi amaliyotlarga amal qilish va potentsial xavfsizlik va unumdorlik oqibatlarini ko'rib chiqish orqali siz FastAPI ning bog'liqlikni kiritish tizimining to'liq salohiyatidan foydalanishingiz mumkin.